/*
 * ArffDataLoader
 * 
 * Project: Search Engine
 * 
 * Copy right 2012 by Phan Hoàn Vũ
 * Email hoanvuphan@gmail.com
 */

package hcmus.fit.ml.tr.data.loader;

import hcmus.fit.ml.tr.data.Instances;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * @author hvp
 * 
 */
public class ArffDataLoader implements DataLoader {

    private static final String DATA_PREFIX = "@data";
    private static final String ATTRIBUTE_PREFIX = "@attribute";
    private static final String RELATIONAL_PREFIX = "@relation";
    private static final String COMMENT_PREFIX = "%";

    private Instances result;
    private LineNumberReader lineReader;
    private String line;

    /**
     * {@inheritDoc}
     */
    public Instances load(String location) {
        try {
            FileReader fr = new FileReader(new File(location));
            this.lineReader = new LineNumberReader(fr);
            this.line = this.lineReader.readLine();
            extractRelational();
            extractAttributes();
            extractData();
            return result;
        } catch (FileNotFoundException e) {
            throw new RuntimeException("File not found in: " + location, e);
        } catch (IOException e) {
            throw new RuntimeException("Error when read file: " + location, e);
        }
    }

    private String readLine() throws IOException {
        if (StringUtils.isNotBlank(this.line)) {
            return this.line;
        }
        while (true) {
            this.line = this.lineReader.readLine();
            if (this.line == null) {
                return null;
            }
            if (StringUtils.isBlank(this.line)) {
                continue;
            }
            if (!StringUtils.startsWith(this.line, COMMENT_PREFIX)) {
                return this.line;
            }
        }
    }

    private void extractRelational() throws IOException {
        while (true) {
            if (this.readLine() == null) {
                return;
            }
            if (StringUtils.startsWith(this.line, RELATIONAL_PREFIX)) {
                this.result = new Instances(this.line.split(" ")[1].trim());
                this.line = null;
                return;
            }
            this.line = null;
        }
    }

    private void extractAttributes() throws IOException {
        boolean reachAttributesRegion = false;
        while (true) {
            if (this.readLine() == null) {
                return;
            }
            if (StringUtils.startsWith(this.line, ATTRIBUTE_PREFIX)) {
                reachAttributesRegion = true;
                String[] attrDescription = this.line.split(" ");
                String value = attrDescription[2].trim();
                if (attrDescription[2].trim().startsWith("{")) {
                    value = StringUtils.join(
                            ArrayUtils.subarray(attrDescription, 2, attrDescription.length), " ")
                            .replace(" ", "");

                }
                this.result.addAttribute(attrDescription[1].trim(), value);
                this.line = null;
            } else {
                if (reachAttributesRegion) {
                    return;
                }
            }
        }
    }

    private void extractData() throws IOException {
        boolean reachDataRegion = false;
        while (true) {
            if (this.readLine() == null) {
                return;
            }
            if (StringUtils.startsWith(this.line, DATA_PREFIX)) {
                reachDataRegion = true;
                this.line = null;
                continue;
            }
            if (reachDataRegion) {
                this.result.addRow(this.line.split(","));
            }
            this.line = null;
        }
    }

}
